// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package typecheck

import (
	"bytes"
	"fmt"
	"sort"
	"strconv"
	"strings"

	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/types"
	"cmd/internal/objabi"
	"cmd/internal/src"
)

func AssignConv(n ir.Node, t *types.Type, context string) ir.Node {
	return assignconvfn(n, t, func() string { return context })
}

// DotImportRefs将导入的标识映射回
// ir。PkgName它们是通过dot导入的。
var DotImportRefs map[*ir.Ident]*ir.PkgName

// LookupNum查找以前缀开头，以
// 小数点n结尾的符号。如果前缀太长，LookupNum会出现恐慌。
func LookupNum(prefix string, n int) *types.Sym {
	var buf [20]byte // 足够长，适合所有当前用户
	copy(buf[:], prefix)
	b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
	return types.LocalPkg.LookupBytes(b)
}

// 给定funarg struct list，返回fn args列表。
func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field {
	var args []*ir.Field
	gen := 0
	for _, t := range tl.Fields().Slice() {
		s := t.Sym
		if mustname && (s == nil || s.Name == "_") {
			// 创造一个名字，这样我们就可以在蹦床中引用它了
			s = LookupNum(".anon", gen)
			gen++
		} else if s != nil && s.Pkg != types.LocalPkg {
			// TODO（mdempsky）：保留原来的位置、名字和包装。
			s = Lookup(s.Name)
		}
		a := ir.NewField(base.Pos, s, nil, t.Type)
		a.Pos = t.Pos
		a.IsDDD = t.IsDDD()
		args = append(args, a)
	}

	return args
}

// newname返回一个与符号s关联的新ONAME节点。
func NewName(s *types.Sym) *ir.Name {
	n := ir.NewNameAt(base.Pos, s)
	n.Curfn = ir.CurFunc
	return n
}

// NodAddr返回一个表示基址处的&n的节点。Pos.
func NodAddr(n ir.Node) *ir.AddrExpr {
	return NodAddrAt(base.Pos, n)
}

// nodAddrPos返回一个节点，在Pos.
func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
	n = markAddrOf(n)
	return ir.NewAddrExpr(pos, n)
}

func markAddrOf(n ir.Node) ir.Node {
	if IncrementalAddrtaken {
		// 我们只能在确定的情况下进行增量addrtaken计算
		// 以检查OADDR的参数。只有在
		// 主类型检查完成，并且不加载内联主体之后，这才是安全的。
		// 需要对OADDR的参数进行类型检查，因为&x[i]接受
		// 如果x是数组，则接受x的地址，如果x是片，则不接受。
		// 注意：在n被选中之前，OuterValue不能正常工作。
		n = typecheck(n, ctxExpr)
		if x := ir.OuterValue(n); x.Op() == ir.ONAME {
			x.Name().SetAddrtaken(true)
		}
	} else {
		// 请记住，我们构建OADDR时没有计算
		// 其参数的Addrtaken位。稍后，我们将使用ComputeAddressTake批量执行此操作。
		DirtyAddrtaken = true
	}
	return n
}

// 如果IncrementalAddressTake为false，则在构建OADDR节点时，我们不会为其计算AddrToken。Addrtaken位由ComputeAddressTake批量设置。
// 如果IncrementalAddressTake为true，则在构建OADDR节点时，其参数的Addrtaken 
// 字段会立即更新。
var IncrementalAddrtaken = false

// 如果DirtyAddrtaken为true，则有OADDR的相应参数
// 尚未标记为Addrtaken。
var DirtyAddrtaken = false

func ComputeAddrtaken(top []ir.Node) {
	for _, n := range top {
		var doVisit func(n ir.Node)
		doVisit = func(n ir.Node) {
			if n.Op() == ir.OADDR {
				if x := ir.OuterValue(n.(*ir.AddrExpr).X); x.Op() == ir.ONAME {
					x.Name().SetAddrtaken(true)
					if x.Name().IsClosureVar() {
						// 将原始变量标记为Addrtaken，以便capturevars 
						// 知道不按值传递它。
						x.Name().Defn.Name().SetAddrtaken(true)
					}
				}
			}
			if n.Op() == ir.OCLOSURE {
				ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doVisit)
			}
		}
		ir.Visit(n, doVisit)
	}
}

func NodNil() ir.Node {
	n := ir.NewNilExpr(base.Pos)
	n.SetType(types.Types[types.TNIL])
	return n
}

// AddImplicitTots在obj中找到缺少的字段。字段
// 将给出最短的唯一地址，
// 将用缺少的字段名修改树。ABCFDG＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊〕。
func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr {
	n.X = typecheck(n.X, ctxType|ctxExpr)
	if n.X.Diag() {
		n.SetDiag(true)
	}
	t := n.X.Type()
	if t == nil {
		return n
	}

	if n.X.Op() == ir.OTYPE {
		return n
	}

	s := n.Sel
	if s == nil {
		return n
	}

	switch path, ambig := dotpath(s, t, nil, false); {
	case path != nil:
		for c := len(path) - 1; c >= 0; c-- {
			dot := ir.NewSelectorExpr(n.Pos(), ir.ODOT, n.X, path[c].field.Sym)
			dot.SetImplicit(true)
			dot.SetType(path[c].field.Type)
			n.X = dot
		}
	case ambig:
		base.Errorf("ambiguous selector %v", n)
		n.X = nil
	}

	return n
}

func CalcMethods(t *types.Type) {
	if t == nil || t.AllMethods().Len() != 0 {
		return
	}

	for _, f := range t.Methods().Slice() {
		f.Sym.SetUniq(true)
	}

	// 生成所有可访问的方法
	slist = slist[:0]
	expand1(t, true)

	// 检查每个方法是否唯一可访问
	var ms []*types.Field
	for i, sl := range slist {
		slist[i].field = nil
		sl.field.Sym.SetUniq(false)

		var f *types.Field
		path, _ := dotpath(sl.field.Sym, t, &f, false)
		if path == nil {
			continue
		}

		// dotpath可能已经挖出了任意字段，我们只需要方法。
		if !f.IsMethod() {
			continue
		}

		// 将其添加到基本类型方法列表
		f = f.Copy()
		f.Embedded = 1 // 需要一个蹦床
		for _, d := range path {
			if d.field.Type.IsPtr() {
				f.Embedded = 2
				break
			}
		}
		ms = append(ms, f)
	}

	for _, f := range t.Methods().Slice() {
		f.Sym.SetUniq(false)
	}

	ms = append(ms, t.Methods().Slice()...)
	sort.Sort(types.MethodsByName(ms))
	t.SetAllMethods(ms)
}

// adddot1返回类型t中深度d处名为s的字段或方法的数量。
// 如果正好存在一个，将在*save（如果save不是nil）中返回，
// 并且dotlist将包含为找到它而遍历的嵌入字段的路径，
// 顺序相反。如果不存在，more将指示t在深度d处是否包含任何
// 嵌入字段，因此调用方可以决定是否在深度更大的
// 处重试。我们已经到达目标深度。如果t有任何字段/方法
func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
	if t.Recur() {
		return
	}
	t.SetRecur(true)
	defer t.SetRecur(false)

	var u *types.Type
	d--
	if d < 0 {
		// 命名为s，那么我们就完成了。否则，我们仍然需要检查下面的
		// 中的嵌入字段。
		c = lookdot0(s, t, save, ignorecase)
		if c != 0 {
			return c, false
		}
	}

	u = t
	if u.IsPtr() {
		u = u.Elem()
	}
	if !u.IsStruct() && !u.IsInterface() {
		return c, false
	}

	var fields *types.Fields
	if u.IsStruct() {
		fields = u.Fields()
	} else {
		fields = u.AllMethods()
	}
	for _, f := range fields.Slice() {
		if f.Embedded == 0 || f.Sym == nil {
			continue
		}
		if d < 0 {
			// 在目标深度发现一个嵌入字段。
			return c, true
		}
		a, more1 := adddot1(s, f.Type, d, save, ignorecase)
		if a != 0 && c == 0 {
			dotlist[d].field = f
		}
		c += a
		if more1 {
			more = true
		}
	}

	return c, more
}

// 点列表由adddot1用来记录嵌入字段的路径
// 用于访问目标字段或方法。
// 必须为非nil，这样即使d为零，dotpath也会返回一个非nil切片。
var dotlist = make([]dlist, 10)

// 将用于赋值的节点n转换为类型t。
func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
	if n == nil || n.Type() == nil || n.Type().Broke() {
		return n
	}

	if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL {
		base.Errorf("use of untyped nil")
	}

	n = convlit1(n, t, false, context)
	if n.Type() == nil {
		return n
	}
	if t.Kind() == types.TBLANK {
		return n
	}

	// 将理想布尔从比较转换为普通布尔
	// 如果下一步是非布尔（如接口{}）。
	if n.Type() == types.UntypedBool && !t.IsBoolean() {
		if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL {
			r := ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
			r.SetType(types.Types[types.TBOOL])
			r.SetTypecheck(1)
			r.SetImplicit(true)
			n = r
		}
	}

	if types.Identical(n.Type(), t) {
		return n
	}

	op, why := Assignop(n.Type(), t)
	if op == ir.OXXX {
		base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
		op = ir.OCONV
	}

	r := ir.NewConvExpr(base.Pos, op, t, n)
	r.SetTypecheck(1)
	r.SetImplicit(true)
	return r
}

// 类型src赋值与类型dst兼容吗？
// 如果是，请返回用于转换的操作码。
// 如果没有，请返回OXXX。在这种情况下，字符串返回参数可能包含一个原因。在所有其他情况下，它将是空字符串。
func Assignop(src, dst *types.Type) (ir.Op, string) {
	if src == dst {
		return ir.OCONVNOP, ""
	}
	if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
		return ir.OXXX, ""
	}

	// 1。src类型与dst相同。
	if types.Identical(src, dst) {
		return ir.OCONVNOP, ""
	}
	return Assignop1(src, dst)
}

func Assignop1(src, dst *types.Type) (ir.Op, string) {
	// 2。src和dst具有相同的基础类型和
	// a。src或dst不是命名类型，或
	// b。两者都是空接口类型，或
	// c。至少有一个是gcshape类型。
	// 对于可分配但不同的非空接口类型，
	// 我们想重新计算itab。重新计算itab可确保
	// itab是唯一的（因此，具有编译时
	// 类型I的接口具有具有接口类型I的itab）。
	if types.Identical(src.Underlying(), dst.Underlying()) {
		if src.IsEmptyInterface() {
			// 两个空接口之间的转换
			// 不需要代码。
			return ir.OCONVNOP, ""
		}
		if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() {
			// 两种类型之间的转换，至少一种未命名的
			// 不需要转换。例外情况是非空接口
			// 需要更新其itab。
			return ir.OCONVNOP, ""
		}
		if src.IsShape() || dst.IsShape() {
			// 形状类型和其中一个类型之间的转换
			// 它所代表的形状类型也不需要转换。
			return ir.OCONVNOP, ""
		}
	}

	// 3。dst是一种接口类型，src实现dst。
	if dst.IsInterface() && src.Kind() != types.TNIL {
		var missing, have *types.Field
		var ptr int
		if src.IsShape() {
			// 形状类型实现了它们已经实现的东西
			// 已经过类型检查以实现，即使它们没有用于它们的方法。
			return ir.OCONVIFACE, ""
		}
		if implements(src, dst, &missing, &have, &ptr) {
			return ir.OCONVIFACE, ""
		}

		// 无论如何，我们都会抱怨这种方法，抑制虚假消息。
		if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
			return ir.OCONVIFACE, ""
		}

		var why string
		if isptrto(src, types.TINTER) {
			why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
		} else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
			why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
		} else if have != nil && have.Sym == missing.Sym {
			why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
				"\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
		} else if ptr != 0 {
			why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
		} else if have != nil {
			why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
				"\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
		} else {
			why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
		}

		return ir.OXXX, why
	}

	if isptrto(dst, types.TINTER) {
		why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
		return ir.OXXX, why
	}

	if src.IsInterface() && dst.Kind() != types.TBLANK {
		var missing, have *types.Field
		var ptr int
		var why string
		if implements(dst, src, &missing, &have, &ptr) {
			why = ": need type assertion"
		}
		return ir.OXXX, why
	}

	// 4。src是双向通道值，dst是通道类型，
	// src和dst具有相同的元素类型，
	// src或dst都不是命名类型。
	if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
		if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) {
			return ir.OCONVNOP, ""
		}
	}

	// 5。src是预先声明的标识符nil，dst是可为零的类型。
	if src.Kind() == types.TNIL {
		switch dst.Kind() {
		case types.TPTR,
			types.TFUNC,
			types.TMAP,
			types.TCHAN,
			types.TINTER,
			types.TSLICE:
			return ir.OCONVNOP, ""
		}
	}

	// 6。关于非类型化常量的规则-已由DefaultLit转换。

	// 7。任何类型的值都可以分配给空白标识符。
	if dst.Kind() == types.TBLANK {
		return ir.OCONVNOP, ""
	}

	return ir.OXXX, ""
}

// 我们能把src类型的值转换成dst类型的值吗？
// 如果是，请返回用于转换的操作码（可能是OCONVNOP）。
// 如果没有，请返回OXXX。在这种情况下，字符串返回参数可能包含一个原因。在所有其他情况下，它将是空字符串。
// srccontent表示src类型的值是否为常量。
func Convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
	if src == dst {
		return ir.OCONVNOP, ""
	}
	if src == nil || dst == nil {
		return ir.OXXX, ""
	}

	// 不允许从常规转换为go:notinheap 
	// （除非不安全。指针）。这些是特定于运行时的
	// 规则。
	// /（a）不允许（*T）到（*U）其中T是go:notinheap，但U不是。
	if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
		why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
		return ir.OXXX, why
	}
	// /（b）不允许字符串到[]T其中T是go:notinheap。
	if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) {
		why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
		return ir.OXXX, why
	}

	// 1。src可以分配给dst。
	op, why := Assignop(src, dst)
	if op != ir.OXXX {
		return op, why
	}

	// 接口规则在转换中与赋值中没有区别。如果涉及到接口，请立即停止
	// 并从assignop收到好消息。
	// 否则清除错误。
	if src.IsInterface() || dst.IsInterface() {
		return ir.OXXX, why
	}

	// 2。忽略结构标记，src和dst具有相同的底层类型。
	if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) {
		return ir.OCONVNOP, ""
	}

	// 3。src和dst是未命名的指针类型，忽略结构标记，
	// 它们的基类型具有相同的底层类型。
	if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil {
		if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) {
			return ir.OCONVNOP, ""
		}
	}

	// 4。src和dst都是整数或浮点类型。
	if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
		if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
			return ir.OCONVNOP, ""
		}
		return ir.OCONV, ""
	}

	// 5。src和dst都是复杂类型。
	if src.IsComplex() && dst.IsComplex() {
		if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
			return ir.OCONVNOP, ""
		}
		return ir.OCONV, ""
	}

	// 常量转换的特殊情况：任何数字
	// 转换都可能是正确的。我们将在evconst中进一步验证
	// 。见#38117。
	if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
		return ir.OCONV, ""
	}

	// 6。src是一个整数，或具有类型[]字节或[]符文
	// 且dst是字符串类型。
	if src.IsInteger() && dst.IsString() {
		return ir.ORUNESTR, ""
	}

	if src.IsSlice() && dst.IsString() {
		if src.Elem().Kind() == types.ByteType.Kind() {
			return ir.OBYTES2STR, ""
		}
		if src.Elem().Kind() == types.RuneType.Kind() {
			return ir.ORUNES2STR, ""
		}
	}

	// 7。src是字符串，dst是[]字节或[]符文。
	// 要切片的字符串。
	if src.IsString() && dst.IsSlice() {
		if dst.Elem().Kind() == types.ByteType.Kind() {
			return ir.OSTR2BYTES, ""
		}
		if dst.Elem().Kind() == types.RuneType.Kind() {
			return ir.OSTR2RUNES, ""
		}
	}

	// 8。src是指针或uintptr，dst不安全。指针。
	if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
		return ir.OCONVNOP, ""
	}

	// 9。src是不安全的。指针和dst是指针或uintptr。
	if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
		return ir.OCONVNOP, ""
	}

	// 10。src是map，dst是指向相应hmap的指针。
	// 实现细节需要此规则，即
	// go gc映射被实现为指向hmap结构的指针。
	if src.Kind() == types.TMAP && dst.IsPtr() &&
		src.MapType().Hmap == dst.Elem() {
		return ir.OCONVNOP, ""
	}

	// 11。src是一个切片，dst是指向数组的指针。
	// 它们必须具有相同的元素类型。
	if src.IsSlice() && dst.IsPtr() && dst.Elem().IsArray() &&
		types.Identical(src.Elem(), dst.Elem().Elem()) {
		if !types.AllowsGoVersion(curpkg(), 1, 17) {
			return ir.OXXX, ":\n\tconversion of slices to array pointers only supported as of -lang=go1.17"
		}
		return ir.OSLICE2ARRPTR, ""
	}

	return ir.OXXX, ""
}

// 解析嵌入类型中省略点的代码。

// 数据列表存储指向嵌入在
// 结构或着色类型中的TFIELD类型的指针。
type dlist struct {
	field *types.Field
}

// 点路径计算唯一的最短显式选择器路径，以完全限定
// 选择表达式x.f，其中x为t类型，f为符号s。
// 如果不存在此类路径，点路径返回零。
// 如果有多条最短路径到达同一深度，则ambig为真。
func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []dlist, ambig bool) {
	// 在结构中嵌入类型会在
	// 类型上施加一个树结构：结构是它们嵌入的类型的父级，而类型是它们的
	// 字段或方法的父级。我们的目标是找到最短路径
	// 在以t为根的子树中，一个名为s的字段或方法。为了实现
	// 这一点，我们迭代地执行深度递增的深度优先搜索
	// 直到找到指定的字段/方法或耗尽树。
	for d := 0; ; d++ {
		if d > len(dotlist) {
			dotlist = append(dotlist, dlist{})
		}
		if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
			return dotlist[:d], false
		} else if c > 1 {
			return nil, true
		} else if !more {
			return nil, false
		}
	}
}

func expand0(t *types.Type) {
	u := t
	if u.IsPtr() {
		u = u.Elem()
	}

	if u.IsInterface() {
		for _, f := range u.AllMethods().Slice() {
			if f.Sym.Uniq() {
				continue
			}
			f.Sym.SetUniq(true)
			slist = append(slist, symlink{field: f})
		}

		return
	}

	u = types.ReceiverBaseType(t)
	if u != nil {
		for _, f := range u.Methods().Slice() {
			if f.Sym.Uniq() {
				continue
			}
			f.Sym.SetUniq(true)
			slist = append(slist, symlink{field: f})
		}
	}
}

func expand1(t *types.Type, top bool) {
	if t.Recur() {
		return
	}
	t.SetRecur(true)

	if !top {
		expand0(t)
	}

	u := t
	if u.IsPtr() {
		u = u.Elem()
	}

	if u.IsStruct() || u.IsInterface() {
		var fields *types.Fields
		if u.IsStruct() {
			fields = u.Fields()
		} else {
			fields = u.AllMethods()
		}
		for _, f := range fields.Slice() {
			if f.Embedded == 0 {
				continue
			}
			if f.Sym == nil {
				continue
			}
			expand1(f.Type, false)
		}
	}

	t.SetRecur(false)
}

func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
	if t == nil {
		return nil, false
	}

	path, ambig := dotpath(s, t, &m, ignorecase)
	if path == nil {
		if ambig {
			base.Errorf("%v.%v is ambiguous", t, s)
		}
		return nil, false
	}

	for _, d := range path {
		if d.field.Type.IsPtr() {
			followptr = true
			break
		}
	}

	if !m.IsMethod() {
		base.Errorf("%v.%v is a field, not a method", t, s)
		return nil, followptr
	}

	return m, followptr
}

// implements报告t是否实现接口iface。t可以是
// 接口、类型参数或具体类型。如果implements返回
// false，它将存储未在*m中实现的iface方法。如果
// 方法名称匹配但类型错误，它将在*samename中另外存储方法（在t上）的类型
// 。
func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
	t0 := t
	if t == nil {
		return false
	}

	if t.IsInterface() || t.IsTypeParam() {
		if t.IsTypeParam() {
			// 如果t是一个简单的类型参数t，那么它的类型和基础是相同的。
			// 如果t是一个类型定义：'type P[t any]t'，它的类型是P[t]，它的
			// 基础是t。因此我们使用't.underground（）！=我们无法区分它们。
			if t.Underlying() != t {
				CalcMethods(t)
			} else {
				// 如果类型绑定的
				// 具有该接口的所有方法，则typeparam满足该接口。
				t = t.Bound()
			}
		}
		i := 0
		tms := t.AllMethods().Slice()
		for _, im := range iface.AllMethods().Slice() {
			for i < len(tms) && tms[i].Sym != im.Sym {
				i++
			}
			if i == len(tms) {
				*m = im
				*samename = nil
				*ptr = 0
				return false
			}
			tm := tms[i]
			if !types.Identical(tm.Type, im.Type) {
				*m = im
				*samename = tm
				*ptr = 0
				return false
			}
		}

		return true
	}

	t = types.ReceiverBaseType(t)
	var tms []*types.Field
	if t != nil {
		CalcMethods(t)
		tms = t.AllMethods().Slice()
	}
	i := 0
	for _, im := range iface.AllMethods().Slice() {
		if im.Broke() {
			continue
		}
		for i < len(tms) && tms[i].Sym != im.Sym {
			i++
		}
		if i == len(tms) {
			*m = im
			*samename, _ = ifacelookdot(im.Sym, t, true)
			*ptr = 0
			return false
		}
		tm := tms[i]
		if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
			*m = im
			*samename = tm
			*ptr = 0
			return false
		}
		followptr := tm.Embedded == 2

		// 如果指针接收器在方法中，
		// 对于值类型，该方法不存在。
		rcvr := tm.Type.Recv().Type
		if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) {
			if false && base.Flag.LowerR != 0 {
				base.Errorf("interface pointer mismatch")
			}

			*m = im
			*samename = nil
			*ptr = 1
			return false
		}
	}

	return true
}

func isptrto(t *types.Type, et types.Kind) bool {
	if t == nil {
		return false
	}
	if !t.IsPtr() {
		return false
	}
	t = t.Elem()
	if t == nil {
		return false
	}
	if t.Kind() != et {
		return false
	}
	return true
}

// lookdot0返回与类型t关联的名为s的字段或方法的数量。如果正好存在一个字段或方法，则将在*save 
// （如果save不是nil）中返回。
func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
	u := t
	if u.IsPtr() {
		u = u.Elem()
	}

	c := 0
	if u.IsStruct() || u.IsInterface() {
		var fields *types.Fields
		if u.IsStruct() {
			fields = u.Fields()
		} else {
			fields = u.AllMethods()
		}
		for _, f := range fields.Slice() {
			if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
				if save != nil {
					*save = f
				}
				c++
			}
		}
	}

	u = t
	if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() {
		// 如果t是定义的指针类型，那么x.m是（*x）的缩写。m、 
		u = t.Elem()
	}
	u = types.ReceiverBaseType(u)
	if u != nil {
		for _, f := range u.Methods().Slice() {
			if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
				if save != nil {
					*save = f
				}
				c++
			}
		}
	}

	return c
}

var slist []symlink

// 用于帮助为嵌入式
// 类型上的方法生成蹦床函数的代码。这些例程与相应的AddImplicitTots 
// 例程大致相同，只是它们希望用唯一的任务调用，而
// 它们返回实际的方法。

type symlink struct {
	field *types.Field
}

// TypesOf将节点列表转换为这些节点类型的列表
// 。
func TypesOf(x []ir.Node) []*types.Type {
	r := make([]*types.Type, len(x))
	for i, n := range x {
		r[i] = n.Type()
	}
	return r
}

// addTargs将TARG以逗号分隔的列表形式写入缓冲区b，并用括号括起来。
func addTargs(b *bytes.Buffer, targs []*types.Type) {
	b.WriteByte('[')
	for i, targ := range targs {
		if i > 0 {
			b.WriteByte(',')
		}
		// 确保类型参数（包括类型参数）是唯一指定的。LinkString（）消除所有空格
		// 并包括包路径（本地包路径在
		// 链接器替换之前为“”。
		tstring := targ.LinkString()
		b.WriteString(tstring)
	}
	b.WriteString("]")
}

// InstTypeName基于
// 泛型类型和类型参数的名称，为实例化的类型创建名称。
func InstTypeName(name string, targs []*types.Type) string {
	b := bytes.NewBufferString(name)
	addTargs(b, targs)
	return b.String()
}

// makeInstName1返回用
// 给定类型实例化的泛型函数的名称，这些类型可以有类型参数或形状，也可以是具体类型。name是
// 泛型函数或方法的名称。
func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
	b := bytes.NewBufferString("")
	i := strings.Index(name, "[")
	assert(hasBrackets == (i >= 0))
	if i >= 0 {
		b.WriteString(name[0:i])
	} else {
		b.WriteString(name)
	}
	addTargs(b, targs)
	if i >= 0 {
		i2 := strings.LastIndex(name[i:], "]")
		assert(i2 >= 0)
		b.WriteString(name[i+i2+1:])
	}
	return b.String()
}

// MakeFuncInstSym根据函数gf和目标的名称，为模版通用函数或方法生成唯一的符号。它将替换名称中现有的任何
// 括号类型列表。MakeInstName声明gf在其名称中有
// 括号，当且仅当has括号为true时。
// 
// 声明的泛型函数的名称最初没有括号，因此hasBracts 
// 应该为false。泛型方法的名称已经有括号，因为新的
// type参数是在接收器的泛型类型中指定的（例如func 
// （func（v*value[T]）。集合（…）{ ... } 具有原始名称（*值[T]）。设置
// 
// 函数的标准命名类似于：“genFn[int，bool]”，而
// /'（*genType[int，bool]）。方法的methodName’
// 
// isMethodNode指定是否正在生成方法节点的名称（与
// 泛型函数实例化的名称或帮助实现实例化类型方法的基于形状的
// 函数的名称相反）。对于形状类型上的方法节点
// 我们在“nofunc.”前面加上前缀，因为形状类型的方法节点
// 没有主体，我们希望避免与基于形状的函数
// 发生名称冲突，该函数有助于为完全实例化的类型实现相同的方法。函数名
// 也创建在（*Tsubster）的末尾。typ1，所以我们在那里附加“nofunc”作为
// well，根据需要。
func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, isMethodNode, hasBrackets bool) *types.Sym {
	nm := makeInstName1(gf.Name, targs, hasBrackets)
	if targs[0].HasShape() && isMethodNode {
		nm = "nofunc." + nm
	}
	return gf.Pkg.Lookup(nm)
}

func MakeDictSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
	for _, targ := range targs {
		if targ.HasTParam() {
			fmt.Printf("FUNCTION %s\n", gf.Name)
			for _, targ := range targs {
				fmt.Printf("  PARAM %+v\n", targ)
			}
			panic("dictionary should always have concrete type args")
		}
	}
	name := makeInstName1(gf.Name, targs, hasBrackets)
	name = fmt.Sprintf("%s.%s", objabi.GlobalDictPrefix, name)
	return gf.Pkg.Lookup(name)
}

func assert(p bool) {
	base.Assert(p)
}

// 应生成其方法的新完全实例化类型的列表。
var instTypeList []*types.Type

// NeedInstType将一个新的完全实例化的类型添加到instTypeList中。
func NeedInstType(t *types.Type) {
	instTypeList = append(instTypeList, t)
}

// GetInstTypeList返回instTypeList的当前内容。
func GetInstTypeList() []*types.Type {
	r := instTypeList
	return r
}

// ClearInstTypeList清除instTypeList的内容。
func ClearInstTypeList() {
	instTypeList = nil
}

// 通用类型替换程序，用于将typeparams替换为类型args。
type Tsubster struct {
	Tparams []*types.Type
	Targs   []*types.Type
	// 如果非nil，则表示从泛型函数中的name节点到新模板函数中的
	// name节点的替换映射。
	Vars map[*ir.Name]*ir.Name
	// 如果非nil，则使用函数替换不完整（TFORW）类型。
	SubstForwFunc func(*types.Type) *types.Type
}

// Typ计算通过用subst.Targs中相应的类型参数替换subst.tparms中出现的t 
// 中的任何类型参数或形状而获得的类型。
// 如果t不包含类型参数，则结果为t；否则，结果将是一个新的
// 类型。它通过使用TFORW类型并通过sym查找部分或
// 完全创建的类型来处理递归类型。Def。
func (ts *Tsubster) Typ(t *types.Type) *types.Type {
	// 在我们完全定义了
	// （可能是递归的）顶级类型之前，请推迟CheckSize调用。
	types.DeferCheckSize()
	r := ts.typ1(t)
	types.ResumeCheckSize()
	return r
}

func (ts *Tsubster) typ1(t *types.Type) *types.Type {
	if !t.HasTParam() && !t.HasShape() && t.Kind() != types.TFUNC {
		// 注意：函数类型无论如何都需要复制，因为
		// 闭包类型可能包含需要复制
		// 的声明。见#45738。ABCFDG 
		return t
	}

	if t.IsTypeParam() || t.IsShape() {
		for i, tp := range ts.Tparams {
			if tp == t {
				return ts.Targs[i]
			}
		}
		// 可能会使用这个定义，这样我们就可以有一个T 
		// 类型的变体，我们可以添加新的方法。假设t是对
		// P[t]的引用。t的名字是“P[t]”，但它的种类是TTYPEPARAM，
		// 因为P[t]被定义为t。如果我们看一下t.underful（），它
		// 是不同的，因为t.underful（）的名字是“t”，而不是“P[t]”。但是，t.underground（）的类型也是TTYPEPARAM。
		// 在本例中，我们在下面的
		// case语句中执行所需的递归替换。
		if t.Underlying() == t {
			// t是一个简单的typeparam，与tparam中的任何内容都不匹配
			return t
		}
		// t是一个更复杂的typeparam（例如，P[t]，如上所述，其
		// 定义就是t）。
		assert(t.Sym() != nil)
	}

	var newsym *types.Sym
	var neededTargs []*types.Type
	var targsChanged bool
	var forw *types.Type

	if t.Sym() != nil && (t.HasTParam() || t.HasShape()) {
		// 由于上述特殊的TFUNC情况，需要再次测试t.HasTParam（）。
		// 根据
		// subst.
		neededTargs = make([]*types.Type, len(t.RParams()))
		for i, rparam := range t.RParams() {
			neededTargs[i] = ts.typ1(rparam)
			if !types.IdenticalStrict(neededTargs[i], rparam) {
				targsChanged = true
			}
		}
		// 的tparam/targs映射，翻译此类型的类型参数。对于命名（定义）类型，我们还必须更改
		// 类型的名称。我们先这样做，这样我们就可以查看在这个替换或其他替换过程中是否已经看到这种类型的
		// 定义/替换。
		genName := genericTypeName(t.Sym())
		newsym = t.Sym().Pkg.Lookup(InstTypeName(genName, neededTargs))
		if newsym.Def != nil {
			// 我们已经创建了这个实例化的定义类型。
			return newsym.Def.Type()
		}

		// 为了处理递归泛型类型，首先创建一个TFORW 
		// 类型，并设置其sym的Def字段，这样，如果该类型在类型中递归出现，就可以找到它。
		forw = NewIncompleteNamedType(t.Pos(), newsym)
		// println（“通过sub创建新类型”，newsym.Name，forw.HasTParam（））
		forw.SetRParams(neededTargs)
		// 从重新实例化的类型（即
		// 基本泛型的符号）复制原始类型。
		assert(t.OrigType() != nil)
		forw.SetOrigType(t.OrigType())
	}

	var newt *types.Type

	switch t.Kind() {
	case types.TTYPEPARAM:
		if t.Sym() == newsym && !targsChanged {
			// 替换没有改变类型。
			return t
		}
		// 替换底层的typeparam（例如P[T]中的T），参见上面描述P[T]类型的示例。
		newt = ts.typ1(t.Underlying())
		assert(newt != t)

	case types.TARRAY:
		elem := t.Elem()
		newelem := ts.typ1(elem)
		if newelem != elem || targsChanged {
			newt = types.NewArray(newelem, t.NumElem())
		}

	case types.TPTR:
		elem := t.Elem()
		newelem := ts.typ1(elem)
		if newelem != elem || targsChanged {
			newt = types.NewPtr(newelem)
		}

	case types.TSLICE:
		elem := t.Elem()
		newelem := ts.typ1(elem)
		if newelem != elem || targsChanged {
			newt = types.NewSlice(newelem)
		}

	case types.TSTRUCT:
		newt = ts.tstruct(t, targsChanged)
		if newt == t {
			newt = nil
		}

	case types.TFUNC:
		newrecvs := ts.tstruct(t.Recvs(), false)
		newparams := ts.tstruct(t.Params(), false)
		newresults := ts.tstruct(t.Results(), false)
		// 翻译签名的图片。
		newtparams := ts.tstruct(t.TParams(), false)
		if newrecvs != t.Recvs() || newparams != t.Params() ||
			newresults != t.Results() || newtparams != t.TParams() || targsChanged {
			// 如果任何类型已更改，则必须复制recv、params和results的所有字段
			// ，因为它们具有依赖的
			// 偏移字段，因此每个新签名都必须有独立的
			// 副本。
			var newrecv *types.Field
			if newrecvs.NumFields() > 0 {
				if newrecvs == t.Recvs() {
					newrecvs = ts.tstruct(t.Recvs(), true)
				}
				newrecv = newrecvs.Field(0)
			}
			if newparams == t.Params() {
				newparams = ts.tstruct(t.Params(), true)
			}
			if newresults == t.Results() {
				newresults = ts.tstruct(t.Results(), true)
			}
			var tparamfields []*types.Field
			if newtparams.HasTParam() {
				tparamfields = newtparams.FieldSlice()
			} else {
				// 如果Tparam现在是具体类型，则从生成的
				// 签名中完全删除Tparam。
				tparamfields = nil
			}
			newt = types.NewSignature(t.Pkg(), newrecv, tparamfields,
				newparams.FieldSlice(), newresults.FieldSlice())
		}

	case types.TINTER:
		newt = ts.tinter(t, targsChanged)
		if newt == t {
			newt = nil
		}

	case types.TMAP:
		newkey := ts.typ1(t.Key())
		newval := ts.typ1(t.Elem())
		if newkey != t.Key() || newval != t.Elem() || targsChanged {
			newt = types.NewMap(newkey, newval)
		}

	case types.TCHAN:
		elem := t.Elem()
		newelem := ts.typ1(elem)
		if newelem != elem || targsChanged {
			newt = types.NewChan(newelem, t.ChanDir())
		}
	case types.TFORW:
		if ts.SubstForwFunc != nil {
			return ts.SubstForwFunc(forw)
		} else {
			assert(false)
		}
	case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64,
		types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64,
		types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128, types.TUNSAFEPTR:
		newt = t.Underlying()
	case types.TUNION:
		nt := t.NumTerms()
		newterms := make([]*types.Type, nt)
		tildes := make([]bool, nt)
		changed := false
		for i := 0; i < nt; i++ {
			term, tilde := t.Term(i)
			tildes[i] = tilde
			newterms[i] = ts.typ1(term)
			if newterms[i] != term {
				changed = true
			}
		}
		if changed {
			newt = types.NewUnion(newterms, tildes)
		}
	default:
		panic(fmt.Sprintf("Bad type in (*TSubster).Typ: %v", t.Kind()))
	}
	if newt == nil {
		// 即使类型中有typeparams，如果这是函数调用的函数类型，可能不会有任何更改（这将在函数实例化中有自己的tparams/targets）。
		return t
	}

	if forw != nil {
		forw.SetUnderlying(newt)
		newt = forw
	}

	if !newt.HasTParam() && !newt.IsFuncArgStruct() {
		// 计算创建的任何新类型的大小。这些将被
		// 延迟到顶级的ts.Typ（）或g.Typ（）（如果这是
		// 从g.fillinMethods（）调用）。
		types.CheckSize(newt)
	}

	if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
		// 填写新类型的方法信息。
		var newfields []*types.Field
		newfields = make([]*types.Field, t.Methods().Len())
		for i, f := range t.Methods().Slice() {
			t2 := ts.typ1(f.Type)
			oldsym := f.Nname.Sym()

			// 使用被替换接收器的名称来创建
			// 方法名称，因为接收器名称可能有许多层次的嵌套（括号）与要替换的类型名称。
			recvType := t2.Recv().Type
			var nm string
			if recvType.IsPtr() {
				recvType = recvType.Elem()
				nm = "(*" + recvType.Sym().Name + ")." + f.Sym.Name
			} else {
				nm = recvType.Sym().Name + "." + f.Sym.Name
			}
			if recvType.RParams()[0].HasShape() {
				// 我们在shape类型的方法中添加了“nofunc”，以避免
				// 与基于形状的帮助程序的名称冲突
				// 函数。请参阅Makefuncintsym的标题注释。
				nm = "nofunc." + nm
			}
			newsym := oldsym.Pkg.Lookup(nm)
			var nname *ir.Name
			if newsym.Def != nil {
				nname = newsym.Def.(*ir.Name)
			} else {
				nname = ir.NewNameAt(f.Pos, newsym)
				nname.SetType(t2)
				ir.MarkFunc(nname)
				newsym.Def = nname
			}
			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
			newfields[i].Nname = nname
		}
		newt.Methods().Set(newfields)
		if !newt.HasTParam() && !newt.HasShape() {
			// 为新的完全实例化类型生成所有方法。

			NeedInstType(newt)
		}
	}
	return newt
}

// t结构在结构类型的字段类型中替换类型参数。对于
// 每个字段，tstruct复制Nname，如果Nname在
// ts.vars中，则将其翻译。始终强制创建新的（顶级）结构
// 无论结构的
// 字段的类型或名称是否有任何更改，请将force设置为true。
func (ts *Tsubster) tstruct(t *types.Type, force bool) *types.Type {
	if t.NumFields() == 0 {
		if t.HasTParam() || t.HasShape() {
			// 对于空结构，如果
			// 从泛型类型或形状类型替换，我们需要返回一个新类型，因为它
			// 将更改HasTParam/HasShape标志。
			return types.NewStruct(t.Pkg(), nil)
		}
		return t
	}
	var newfields []*types.Field
	if force {
		newfields = make([]*types.Field, t.NumFields())
	}
	for i, f := range t.Fields().Slice() {
		t2 := ts.typ1(f.Type)
		if (t2 != f.Type || f.Nname != nil) && newfields == nil {
			newfields = make([]*types.Field, t.NumFields())
			for j := 0; j < i; j++ {
				newfields[j] = t.Field(j)
			}
		}
		if newfields != nil {
			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
			newfields[i].Embedded = f.Embedded
			newfields[i].Note = f.Note
			if f.IsDDD() {
				newfields[i].SetIsDDD(true)
			}
			if f.Nointerface() {
				newfields[i].SetNointerface(true)
			}
			if f.Nname != nil && ts.Vars != nil {
				v := ts.Vars[f.Nname.(*ir.Name)]
				if v != nil {
					// 在这种情况下，我们是
					// 转换我们要替换的函数类型，因此它的dcl在
					// subst.ts.vars表中，我们希望
					// 更改为引用新的dcl。
					newfields[i].Nname = v
				} else {
					// 这里我们是
					// 转换函数的类型
					// 函数中的引用我们是
					// 替换，所以我们保留Nname 
					// 值不变。
					newfields[i].Nname = f.Nname
				}
			}
		}
	}
	if newfields != nil {
		news := types.NewStruct(t.Pkg(), newfields)
		news.StructType().Funarg = t.StructType().Funarg
		return news
	}
	return t

}

// tinter在接口类型的方法类型中替换类型参数。对于空接口，我们需要返回一个新类型，如果从泛型类型或形状类型替换，则返回新类型，因为它将更改HasTParam/HasShape标志。
func (ts *Tsubster) tinter(t *types.Type, force bool) *types.Type {
	if t.Methods().Len() == 0 {
		if t.HasTParam() || t.HasShape() {
			return types.NewInterface(t.Pkg(), nil, false)
		}
		return t
	}
	var newfields []*types.Field
	if force {
		newfields = make([]*types.Field, t.Methods().Len())
	}
	for i, f := range t.Methods().Slice() {
		t2 := ts.typ1(f.Type)
		if (t2 != f.Type || f.Nname != nil) && newfields == nil {
			newfields = make([]*types.Field, t.Methods().Len())
			for j := 0; j < i; j++ {
				newfields[j] = t.Methods().Index(j)
			}
		}
		if newfields != nil {
			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
		}
	}
	if newfields != nil {
		return types.NewInterface(t.Pkg(), newfields, t.IsImplicit())
	}
	return t
}

// genericSym返回由
// sym命名的类型的基泛型类型的名称。它只返回通过删除
// 第一个括号（“[”）后的所有内容而获得的名称。
func genericTypeName(sym *types.Sym) string {
	return sym.Name[0:strings.Index(sym.Name, "[")]
}

// getShapes将类型t中使用的形状类型列表附加到
// listp。类型遍历被简化有两个原因：（1）当t.hashape（）为false时，我们总是可以停止
// 类型遍历；以及（2）形状类型不能出现在命名类型中，除了泛型类型的类型参数。因此，遍历将
// 在我们必须处理递归类型之前总是停止。
func getShapes(t *types.Type, listp *[]*types.Type) {
	if !t.HasShape() {
		return
	}
	if t.IsShape() {
		*listp = append(*listp, t)
		return
	}

	if t.Sym() != nil {
		// 命名类型中不能有形状，除了
		// 泛型类型的类型args。一旦我们在泛型函数（#47631）中
		// alloc local type，我们就必须以不同的方式处理这个问题。
		for _, rparam := range t.RParams() {
			getShapes(rparam, listp)
		}
		return
	}

	switch t.Kind() {
	case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN:
		getShapes(t.Elem(), listp)

	case types.TSTRUCT:
		for _, f := range t.FieldSlice() {
			getShapes(f.Type, listp)
		}

	case types.TFUNC:
		for _, f := range t.Recvs().FieldSlice() {
			getShapes(f.Type, listp)
		}
		for _, f := range t.Params().FieldSlice() {
			getShapes(f.Type, listp)
		}
		for _, f := range t.Results().FieldSlice() {
			getShapes(f.Type, listp)
		}
		for _, f := range t.TParams().FieldSlice() {
			getShapes(f.Type, listp)
		}

	case types.TINTER:
		for _, f := range t.Methods().Slice() {
			getShapes(f.Type, listp)
		}

	case types.TMAP:
		getShapes(t.Key(), listp)
		getShapes(t.Elem(), listp)

	default:
		panic(fmt.Sprintf("Bad type in getShapes: %v", t.Kind()))
	}

}

// Shapify获取一个具体类型和一个类型参数索引，并返回一个GCshape类型，该类型可以用
// 代替输入类型，并且仍然生成相同的代码。
// 未添加任何方法-直接对形状的所有方法调用都应通过使用字典转换为接口来完成。ABCFDG 
// 
// tparam是关联的typeparam-它必须是TTYPEPARAM类型。如果关联的类型param（不常见）有
// 结构类型，则指针类型t 
// 将映射到其基础类型，而不是与其他指针合并。
// 
// 形状类型也通过类型参数/arg 
// 列表中的类型索引来区分。我们需要这样做，以便能够正确地区分和替换同一函数中的两个
// 类型参数，它们对于特定的
// 实例化具有相同的形状。
func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type {
	assert(!t.IsShape())
	if t.HasShape() {
		// 我们有时会处理形状实例化
		// 中的类型，这些类型是从现有形状类型构造而来的，因此t可能
		// 有时其中包含形状类型。在这种情况下，我们用getShapes（）找到所有
		// 这些形状类型，并用它们的
		// 基础类型替换它们。
		// 
		// 如果我们不这样做，我们可能会创建额外的不需要的形状类型，
		// 将这些其他形状类型嵌入其中。这可能会导致
		// 生成额外的形状实例化，以及我们在生成字典时使用的
		// 实例化与实际调用的
		// 实例化之间的不匹配。(#51303). 
		list := []*types.Type{}
		getShapes(t, &list)
		list2 := make([]*types.Type, len(list))
		for i, shape := range list {
			list2[i] = shape.Underlying()
		}
		ts := Tsubster{
			Tparams: list,
			Targs:   list2,
		}
		t = ts.Typ(t)
	}
	// 将具有相同基础类型的所有类型映射到同一形状。
	u := t.Underlying()

	// 所有指针的形状都相同。
	// 待办事项：使不安全。指针的形状与普通指针相同。
	// 注意：数组指针是特殊的，因为切片到数组指针
	// 转换。见第49295期。
	if u.Kind() == types.TPTR && u.Elem().Kind() != types.TARRAY &&
		tparam.Bound().StructuralType() == nil && !u.Elem().NotInHeap() {
		u = types.Types[types.TUINT8].PtrTo()
	}

	if shapeMap == nil {
		shapeMap = map[int]map[*types.Type]*types.Type{}
	}
	submap := shapeMap[index]
	if submap == nil {
		submap = map[*types.Type]*types.Type{}
		shapeMap[index] = submap
	}
	if s := submap[u]; s != nil {
		return s
	}

	// LinkString唯一地指定类型，但没有空格。
	nm := fmt.Sprintf("%s_%d", u.LinkString(), index)
	sym := types.ShapePkg.Lookup(nm)
	if sym.Def != nil {
		// 使用任何同名的现有类型
		submap[u] = sym.Def.Type()
		return submap[u]
	}
	name := ir.NewDeclNameAt(u.Pos(), ir.OTYPE, sym)
	s := types.NewNamed(name)
	sym.Def = name
	s.SetUnderlying(u)
	s.SetIsShape(true)
	s.SetHasShape(true)
	types.CalcSize(s)
	name.SetType(s)
	name.SetTypecheck(1)
	submap[u] = s
	return s
}

var shapeMap map[int]map[*types.Type]*types.Type
